﻿using System;
using System.Web;
using System.Collections.Generic;
using System.IO;

namespace Doo.WebUI
{
    /// <summary>
    /// 此处理程序用于向客户端输出所有控件及其依赖项，用于控件加载器。
    /// </summary>
    public class CustomControlHandler : IHttpHandler
    {
        /// <summary>
        /// 您将需要在您网站的 web.config 文件中配置此处理程序，
        /// 并向 IIS 注册此处理程序，然后才能进行使用。有关详细信息，
        /// 请参见下面的链接: http://go.microsoft.com/?linkid=8101007
        /// </summary>
        #region IHttpHandler Members


        public bool IsReusable
        {
            // 如果无法为其他请求重用托管处理程序，则返回 false。
            // 如果按请求保留某些状态信息，则通常这将为 false。
            get { return true; }
        }

        class ResourceDir
        {
            public string FullPath;

            public Dictionary<string, ResourceDir> Dir = new System.Collections.Generic.Dictionary<string, ResourceDir>();
            /// <summary>
            /// 文件名--资源序号+最后修改时间[如果文件不存在则为-1]
            /// </summary>
            public Dictionary<string, int[]> Files = new System.Collections.Generic.Dictionary<string, int[]>();

        }

        class ResourceM
        {
            public ResourceDir Root = new ResourceDir() { FullPath = "/" };

            Dictionary<string, int> CachedRes = new Dictionary<string, int>();

            /// <summary>
            /// 返回对应的路径
            /// </summary>
            /// <param name="path">路径</param>
            /// <param name="basedir">基准路径，为空则为root</param>
            /// <returns></returns>
            public ResourceDir FindDir(string path, ResourceDir basedir)
            {
                string[] paths = path.Split('/');
                if (basedir == null) basedir = Root;
                foreach (var p in paths)
                {
                    if (p == string.Empty) continue;
                    if (basedir.Dir.ContainsKey(p))
                    {
                        basedir = basedir.Dir[p];
                    }
                    else
                    {
                        ResourceDir newdir = new ResourceDir();
                        basedir.Dir.Add(p, newdir);
                        newdir.FullPath = basedir.FullPath + '/' + p;
                        basedir = newdir;
                    }
                }
                return basedir;
            }

            int index = 0;

            /// <summary>
            /// 添加资源，返回序号。
            /// </summary>
            /// <param name="fullpath"></param>
            /// <returns></returns>
            public int AddResource(ResourceDir basedir, string path, bool needVersion)
            {
                string fullpath = basedir.FullPath + '/' + path;
                if (CachedRes.ContainsKey(fullpath)) return CachedRes[fullpath];

                int i = path.LastIndexOf('/');
                if (i >= 0)
                {
                    basedir = FindDir(path.Substring(0, i), basedir);
                    path = path.Substring(i + 1);
                }

                index++;
                int v = 0;
                if (needVersion)
                {
                    string realpath = HttpContext.Current.Server.MapPath(fullpath);
                    if (File.Exists(realpath))
                    {
                        v = (int)(File.GetLastWriteTime(realpath).Ticks);
                    }
                }
                basedir.Files.Add(path, new int[] { index, v });
                CachedRes.Add(fullpath, index);

                return index;
            }

            public int AddResource(string path, bool needVersion)
            {
                return AddResource(null, path, needVersion);
            }

            public int AddResource(string fullpath)
            {
                return AddResource(fullpath, true);
            }

            public int AddResource(ResourceDir dir, string path)
            {
                return AddResource(dir, path, true);
            }

            /// <summary>
            /// 序列化
            /// </summary>
            /// <param name="dir">肯定有值的目录</param>
            /// <param name="sb"></param>
            void jsonSerDir(ResourceDir dir, System.Text.StringBuilder sb)
            {
                sb.Append('{');

                #region 处理下级目录

                foreach (var d in dir.Dir)
                {
                    sb.AppendFormat("\"{0}\":", d.Key);
                    jsonSerDir(d.Value, sb);
                    sb.Append(",");
                }

                #endregion

                #region 处理文件

                foreach (var d in dir.Files)
                {
                    sb.AppendFormat("\"{0}\":[{1},{2}],", d.Key, d.Value[0], d.Value[1]);//[资源序号，版本号]版本号是最后修改时间
                }

                #endregion

                sb[sb.Length - 1] = '}';
            }

            /// <summary>
            /// 将资源转换成json
            /// </summary>
            /// <returns></returns>
            public string ToJson()
            {
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                jsonSerDir(Root, sb);
                return sb.ToString();
            }
        }

        /// <summary>
        /// 处理请求
        /// </summary>
        /// <param name="context"></param>
        public void ProcessRequest(HttpContext context)
        {
            //查看缓存
            string output = context.Application["__doo__customcontrolhandler"] as string;
            if (output == null)
            {
                Configuation.CustomControlSection config = System.Web.Configuration.WebConfigurationManager.GetSection("customcontrol") as Configuation.CustomControlSection;
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                ResourceM rm = new ResourceM();
                ResourceDir basedir = null;
                Dictionary<string, int> serviceIndex = new Dictionary<string, int>();

                //1.输出webservices
                //格式：Doo.ControlLoader.initDependServices([[name,path,type]]);
                if (config.WebServices.Count > 0)
                {
                    sb.Append("Doo.ControlLoader.initDependServices({");
                    if (!string.IsNullOrEmpty(config.WebServices.BasePath)) basedir = rm.FindDir(config.WebServices.BasePath, null);
                    foreach (Configuation.WebServiceElement ws in config.WebServices)
                    {
                        int i = rm.AddResource(basedir, ws.Path + "/js", false);
                        sb.AppendFormat("\"{0}\":[{1},\"{2}\"],", ws.Name, i, ws.Type);
                        serviceIndex.Add(ws.Name, i);
                    };
                    sb[sb.Length - 1] = '}';
                    //附加基准名字空间
                    sb.AppendFormat(",\"{0}\");", config.WebServices.NameSpace);
                }
                basedir = null;

                //2.输出controls
                //格式：[name,resindex,scripttype,dependservices,dependfiles]
                if (config.Controls.Count > 0)
                {
                    sb.Append("Doo.ControlLoader.initControlDefs({");
                    if (!string.IsNullOrEmpty(config.Controls.BasePath)) basedir = rm.FindDir(config.Controls.BasePath, null);
                    foreach (Configuation.ControlElement ws in config.Controls)
                    {
                        int i = rm.AddResource(basedir, ws.Path);

                        string depends = "0";
                        if (ws.Dependences.Count > 0)
                        {
                            //创建服务依赖组
                            List<string> indexList = new List<string>();
                            foreach (Configuation.DependenceElement de in ws.Dependences)
                            {
                                indexList.Add(serviceIndex[de.Name].ToString());
                            }
                            depends = "[" + string.Join(",", indexList.ToArray()) + "]";
                        }
                        sb.AppendFormat("\"{0}\":[{1},\"{2}\",\"{3}\",{4}],", ws.Name, i, ws.Type, ws.TagName, depends);
                    }
                    sb[sb.Length - 1] = '}';
                    //附加基准名字空间
                    sb.AppendFormat(",\"{0}\",\"{1}\");", config.Controls.NameSpace, config.Controls.TagPreFix);
                }

                //n.处理资源
                output =
                                    string.Format("Doo.ControlLoader.initResources({0});", rm.ToJson())
                                    + sb.ToString();
            }

            context.Response.Write(output);
        }

        #endregion
    }
}
